﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

//TODO: test

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public enum EXHAUSTIVE_TEMPLATE_MATCH_MODE
    {
        /// <summary>
        /// 
        /// </summary>
        NORMAL_CORRELATION,
        /// <summary>
        /// displaced frame difference
        /// </summary>
        DISPLACED_FRAME_DIFFERENCE
    }

    /// <summary>
    /// 
    /// </summary>
    public class ExhaustiveTemplateMatching : BaseImageFilter
    {
        protected UnsafeBitmap m_BitmapTemplate = null;
        protected int m_nSimilarity = 0;

        protected List<SADPosition> aPosition = new List<SADPosition>();

//        ImageMatch[i][j] = 
//
//               SUMu,v {Image[i-u][j-v] * ImageTemplate[l-u][c-v]}
//255 * -----------------------------------------------------------------------
//      SQRT{ SUMu,v {Image[i-u][j-v]^2} * SUMu,v {ImageTemplate[l-u][c-v]^2} }

//        Berechnung der mittleren "displaced frame difference":
//
//ImageMatch[i][j] =
//
// SUMu,v {ABS { Image[i-u][j-v] - ImageTemplate[l-u][c-v] }}     
 //----------------------------------------------------------------------
//                       AREA ( ImageTemplate )       
        /// <summary>
        /// Initializes a new instance of the <see cref="ExhaustiveTemplateMatching"/> class.
        /// </summary>
        public ExhaustiveTemplateMatching()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExhaustiveTemplateMatching"/> class.
        /// </summary>
        public ExhaustiveTemplateMatching(UnsafeBitmap _templateBitmap)
        {
            m_BitmapTemplate = _templateBitmap;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExhaustiveTemplateMatching"/> class.
        /// </summary>
        /// <param name="_exhaustiveTemplateMatching">The _exhaustive template matching.</param>
        internal ExhaustiveTemplateMatching(ExhaustiveTemplateMatching _exhaustiveTemplateMatching)
        {
            m_nSimilarity = _exhaustiveTemplateMatching.m_nSimilarity;
        }

        /// <summary>
        /// Gets or sets the template bitmap.
        /// </summary>
        /// <value>The template bitmap.</value>
        public UnsafeBitmap TemplateBitmap
        {
            get { return m_BitmapTemplate; }
            set { m_BitmapTemplate = value; }
        }

        /// <summary>
        /// Gets or sets the similarity.
        /// </summary>
        /// <value>The similarity.</value>
        public int Similarity
        {
            get { return m_nSimilarity; }
            set { m_nSimilarity = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = new GrayScale().ExecuteCloned(_bitmap);
            int x = 0;
            int y = 0;
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            UnsafeBitmap bitmapTemplateCloned = (UnsafeBitmap)m_BitmapTemplate.Clone();
            new GrayScale().Execute(bitmapTemplateCloned);

            int nTemplateWidth = TemplateBitmap.Width;
            int nTemplateHeight = TemplateBitmap.Height;
            int nTX = 0;
            int nTY = 0;

            int nChannelCount = 3; //this is rgb
            int nMaxDifference = nTemplateWidth * nTemplateHeight * nChannelCount * 255;

            // integer similarity threshold
            int nSimilarityThreshold = 30;
            int nThreshold = (int)(nSimilarityThreshold * nMaxDifference);

            int nDifference = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    for (nTY = 0; nTY < nTemplateHeight; nTY++)
                    {
                        for (nTX = 0; nTX < nTemplateWidth; nTX++)
                        {
                            nDifference = ColorFunctions.DistanceSquared(_bitmap.GetPixel(x, y), m_BitmapTemplate.GetPixel(nTX, nTY));
                        }
                    }

                    int nSimilarity = nMaxDifference - nDifference;

                    if (nSimilarity < nMaxDifference)
                    {
                        SADPosition sadPosition = new SADPosition();
                        sadPosition.BestRow = y;
                        sadPosition.BestCol = x;
                        sadPosition.BestSAD = nSimilarity;
                        aPosition.Add(sadPosition);
                    }
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ExhaustiveTemplateMatching(this);
        }
    }
}
